package com.roy.minimq.remoting.domain.nettyserver;

import com.roy.minimq.remoting.domain.entity.NettyEvent;
import com.roy.minimq.remoting.domain.entity.NettyEventType;
import com.roy.minimq.remoting.domain.util.RemotingHelper;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 服务端的连接管理器需要保留长连接的列表。
 */
@ChannelHandler.Sharable
public class NettyServerConnectManageHandler extends ChannelInboundHandlerAdapter {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private NettyRemotingServer remotingServer;

    public NettyServerConnectManageHandler(NettyRemotingServer remotingServer) {
        this.remotingServer = remotingServer;
    }

    //将连接变化情况广播出去。
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
        logger.info("NETTY SERVER PIPELINE: channelInactive, the channel[{}]", remoteAddr);
        this.remotingServer.putNettyEvent(new NettyEvent(NettyEventType.CONNECT,remoteAddr,ctx.channel()));

        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
        logger.info("NETTY SERVER PIPELINE: channelInactive, the channel[{}]", remoteAddr);
        if(null != this.remotingServer.getChannelEventListener()) {
            this.remotingServer.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddr, ctx.channel()));
        }

        super.channelInactive(ctx);
    }

    //超时断开连接
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if(idleStateEvent.state().equals(IdleState.ALL_IDLE)){
                final String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
                logger.warn("NETTY SERVER PIPELINE: IDLE exception [{}]", remoteAddr);
                ctx.channel().close().addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        logger.info("closeChannel: close the connection to remote address[{}] result: {}", remoteAddr,future.isSuccess());
                    }
                });
                if(null != this.remotingServer.getChannelEventListener()) {
                    this.remotingServer.putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddr, ctx.channel()));
                }
            }
        }

        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        final String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
        logger.warn("NETTY SERVER PIPELINE: exceptionCaught {}", remoteAddr);
        logger.warn("NETTY SERVER PIPELINE: exceptionCaught exception.", cause.getMessage());

        if(null != this.remotingServer.getChannelEventListener()){
            this.remotingServer.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION,remoteAddr,ctx.channel()));
        }

        ctx.channel().close().addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                logger.info("closeChannel: close the connection to remote address[{}] result: {}", remoteAddr,future.isSuccess());
            }
        });

        super.exceptionCaught(ctx, cause);
    }
}
